package com.ctshk.app.user.controller;

import com.alibaba.fastjson.JSONObject;
import com.ctshk.common.annotations.OperationLogAnnotation;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.Assert;
import com.ctshk.common.utils.RSAUtil;
import com.ctshk.rpc.system.dto.MainDataAreaNumberListDTO;
import com.ctshk.rpc.system.req.MainDataAreaNumberListReq;
import com.ctshk.rpc.system.service.IMainDataAreaNumberService;
import com.ctshk.rpc.user.dto.NumDTO;
import com.ctshk.rpc.user.dto.AppUserDTO;
import com.ctshk.rpc.user.req.*;
import com.ctshk.rpc.user.service.IUserService;
import com.ctshk.rpc.user.service.IUserValidateService;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Api(value="用户", tags="用户管理")
@RestController
@RequestMapping("/account")
public class UserController extends AppBaseController {

    @Value("${auth.user.token.timeout.app}")
    private Long tokenTimeoutApp;

    @Value("${auth.user.token.timeout.sapp}")
    private Long tokenTimeoutsApp;

    @DubboReference
    private IUserService userService;

    @DubboReference
    private IUserValidateService userValidateService;

    @DubboReference
    private IMainDataAreaNumberService iMainDataAreaNumberService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @ApiOperation(value="测试接口", notes="浩然测试接口")
    @GetMapping("/test")
    public Result code() {
        return Result.success();
    }

    @ApiOperation(value="密码登录", notes="账号密码登录")
    @PostMapping("/login")
    public Result<AppUserDTO> login(@RequestBody @Valid LoginReq loginReq) throws Exception {
        AppUserDTO u = new AppUserDTO();
        u.setUserAccount(loginReq.getUsername());
        u.setPassword(loginReq.getPassword());

        u = userService.login(u);

        TokenUser tokenUser = new TokenUser();
        tokenUser.setId(u.getId());
        tokenUser.setUsername(loginReq.getUsername());
        tokenUser.setNickname(u.getEnFullname());
        tokenUser.setLoginType(LoginType.APP.getCode());
        tokenUser.setLastLoginTime(LocalDateTime.now());

        String token = RSAUtil.encryptStr(JSONObject.toJSONString(tokenUser));
        u.setToken(token);
        String tokeyKey = RedisConstants.CLIENT_APP_TOKEN_USER_KEY + u.getId();

        redisTemplate.opsForValue().set(tokeyKey, token, tokenTimeoutApp, TimeUnit.DAYS);
        //getResponse().addHeader(RedisConstants.JWT_TOKEN_HEADER, RedisConstants.JWT_TOKEN_PREFIX + token);
        return Result.success(u);

    }

    @ApiOperation(value="验证码登录", notes="验证码登录")
    @PostMapping("/smsLogin")
    public Result<AppUserDTO> smsLogin(@RequestBody @Valid SmsLoginReq smsLoginReq) throws Exception {
        smsLoginReq.setContactMobileAreaCode(replacePlus(smsLoginReq.getContactMobileAreaCode()));
        userValidateService.check(smsLoginReq.getFullContactNumber(),smsLoginReq.getCode(),SmsType.LOGIN.getType());

        AppUserDTO u = userService.loginByPhone(smsLoginReq.getContactMobileAreaCode(),smsLoginReq.getContactNumber());;

        TokenUser tokenUser = new TokenUser();
        tokenUser.setId(u.getId());
        tokenUser.setUsername(u.getUserAccount());
        tokenUser.setNickname(u.getEnFullname());
        tokenUser.setLastLoginTime(LocalDateTime.now());
        tokenUser.setLoginType(LoginType.APP.getCode());
        String token = RSAUtil.encryptStr(JSONObject.toJSONString(tokenUser));
        u.setToken(token);
        String tokeyKey = RedisConstants.CLIENT_APP_TOKEN_USER_KEY + u.getId();

        redisTemplate.opsForValue().set(tokeyKey, token, tokenTimeoutApp, TimeUnit.DAYS);
        //getResponse().addHeader(RedisConstants.JWT_TOKEN_HEADER, RedisConstants.JWT_TOKEN_PREFIX + token);
        return Result.success(u);
    }

    @ApiOperation(value="pc密码登录", notes="pc账号密码登录")
    @PostMapping("/pcLogin")
    public Result<AppUserDTO> pcLogin(@RequestBody @Valid LoginReq loginReq) throws Exception {
        AppUserDTO u = new AppUserDTO();
        u.setUserAccount(loginReq.getUsername());
        u.setPassword(loginReq.getPassword());

        u = userService.login(u);

        TokenUser tokenUser = new TokenUser();
        tokenUser.setId(u.getId());
        tokenUser.setUsername(loginReq.getUsername());
        tokenUser.setNickname(u.getEnFullname());
        tokenUser.setLoginType(LoginType.PC.getCode());
        tokenUser.setLastLoginTime(LocalDateTime.now());

        String token = RSAUtil.encryptStr(JSONObject.toJSONString(tokenUser));
        String tokeyKey = RedisConstants.CLIENT_PC_TOKEN_USER_KEY + u.getId();
        u.setToken(token);
        redisTemplate.opsForValue().set(tokeyKey, token, 7, TimeUnit.DAYS);
        getResponse().addHeader(RedisConstants.JWT_TOKEN_HEADER, RedisConstants.JWT_TOKEN_PREFIX + token);
        return Result.success(u);

    }

    @ApiOperation(value="pc验证码登录", notes="pc验证码登录")
    @PostMapping("/pcSmsLogin")
    public Result<AppUserDTO> pcSmsLogin(@RequestBody @Valid SmsLoginReq smsLoginReq) throws Exception {
        smsLoginReq.setContactMobileAreaCode(replacePlus(smsLoginReq.getContactMobileAreaCode()));
        userValidateService.check(smsLoginReq.getFullContactNumber(),smsLoginReq.getCode(),SmsType.LOGIN.getType());

        AppUserDTO u = userService.noPwdLogin(smsLoginReq.getContactNumber());;

        TokenUser tokenUser = new TokenUser();
        tokenUser.setId(u.getId());
        tokenUser.setUsername(u.getUserAccount());
        tokenUser.setNickname(u.getEnFullname());
        tokenUser.setLastLoginTime(LocalDateTime.now());
        tokenUser.setLoginType(LoginType.PC.getCode());
        String token = RSAUtil.encryptStr(JSONObject.toJSONString(tokenUser));
        String tokeyKey = RedisConstants.CLIENT_PC_TOKEN_USER_KEY + u.getId();
        u.setToken(token);
        redisTemplate.opsForValue().set(tokeyKey, token, 7, TimeUnit.DAYS);
        getResponse().addHeader(RedisConstants.JWT_TOKEN_HEADER, RedisConstants.JWT_TOKEN_PREFIX + token);
        return Result.success(u);
    }

    @ApiOperation(value="pc注册", notes="pc手机+验证码注册")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.OTHER, operTitle = "pc注册", operDesc = "pc注册")
    @PostMapping("/pcRegister")
    public Result<AppUserDTO> pcRegister(@RequestBody @Valid RegisterReq registerReq) throws Exception{
        registerReq.setContactMobileAreaCode(replacePlus(registerReq.getContactMobileAreaCode()));
        Result<AppUserDTO> result = userService.register(registerReq);
        if(result.isSuccess()) {
            AppUserDTO u = result.getData();
            String tokeyKey = RedisConstants.CLIENT_APP_TOKEN_USER_KEY + u.getId();
            TokenUser tokenUser = new TokenUser();
            tokenUser.setId(u.getId());
            tokenUser.setNickname(u.getEnFullname());
            tokenUser.setLoginType(LoginType.APP.getCode());
            tokenUser.setLastLoginTime(LocalDateTime.now());

            String token = RSAUtil.encryptStr(JSONObject.toJSONString(tokenUser));
            u.setToken(token);

            redisTemplate.opsForValue().set(tokeyKey, token, tokenTimeoutsApp, TimeUnit.MINUTES);
        }

        return result;
    }

    @ApiOperation(value="移动端注册", notes="手机+验证码注册")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.ADD, operTitle = "移动端注册", operDesc = "移动端注册")
    @PostMapping("/register")
    public Result<AppUserDTO> register(@RequestBody @Valid RegisterReq registerReq) throws Exception{
        registerReq.setContactMobileAreaCode(replacePlus(registerReq.getContactMobileAreaCode()));
        Result<AppUserDTO> result = userService.register(registerReq);
        if(result.isSuccess()) {
            AppUserDTO u = result.getData();
            String tokeyKey = RedisConstants.CLIENT_APP_TOKEN_USER_KEY + u.getId();

            TokenUser tokenUser = new TokenUser();
            tokenUser.setId(u.getId());
            tokenUser.setNickname(u.getEnFullname());
            tokenUser.setLoginType(LoginType.APP.getCode());
            tokenUser.setLastLoginTime(LocalDateTime.now());

            String token = RSAUtil.encryptStr(JSONObject.toJSONString(tokenUser));
            u.setToken(token);
            redisTemplate.opsForValue().set(tokeyKey, token, tokenTimeoutApp, TimeUnit.DAYS);
        }
        return result;
    }

    @ApiOperation(value="当前用户激活星赏会会员", notes="当前用户激活星赏会会员")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.OTHER, operTitle = "当前用户激活星赏会会员", operDesc = "当前用户激活星赏会会员")
    @PostMapping("/registerStartVip")
    public Result<AppUserDTO> registerStartVip(@RequestBody RegisterStartVipReq req) throws Exception{
        TokenUser currentUser = getCurrentUser();
        req.setUserId(currentUser.getId());
        return userService.registerStartVip(req);
    }

    @ApiOperation(value="短信验证码", notes="短信验证码")
    @PostMapping("/smsCaptcha")
    public Result smsCaptcha(@RequestBody @Valid SmsCaptchaReq req) throws Exception{
        Integer type = req.getType();
        if(StringUtils.isNotBlank(req.getContactMobileAreaCode())) {
            req.setContactMobileAreaCode(replacePlus(req.getContactMobileAreaCode()));
        }
        String contactMobileAreaCode = req.getContactMobileAreaCode();
        String contactNumber = req.getContactNumber();
        Long userId = null;
        TokenUser currentUser = null;
        if(type == 3 || type == 5) {
            currentUser = getCurrentUser();
            userId = currentUser.getId();
        }
        if(currentUser == null) {
            Assert.notBlank(contactMobileAreaCode,SystemError.SYS_430, "手机区号不能为空");
            Assert.notBlank(contactNumber,SystemError.SYS_430, "手机号码不能为空");
        } else {
           if(StringUtils.isNotBlank(contactNumber)) {
               Assert.notBlank(contactMobileAreaCode,SystemError.SYS_430, "手机区号不能为空");
           }
        }
        return userValidateService.sendSmsCaptcha(contactMobileAreaCode,contactNumber,type,userId);
    }

    @ApiOperation(value="重置密碼", notes="重置密碼")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.UPDATE, operTitle = "重置密碼", operDesc = "重置密碼-此方法无需登录通过手机认证")
    @PostMapping("/reset/new/password")
    public Result resetPass(@RequestBody @Valid ForgetPwdReq forgetPwdReq) throws Exception{
        forgetPwdReq.setContactMobileAreaCode(replacePlus(forgetPwdReq.getContactMobileAreaCode()));
        return userService.resetPass(forgetPwdReq);
    }

    @ApiOperation(value="发送邮箱驗證碼", notes="发送邮箱驗證碼-修改邮箱使用")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.OTHER, operTitle = "发送邮箱", operDesc = "发送邮箱-忘记密码使用")
    @PostMapping("/mail/send")
    public Result mail(@RequestBody EmailReq req) {
        TokenUser currentUser = getCurrentUser();
        return userService.mail(req.getEmail(),currentUser.getId());
    }

    @ApiOperation(value="发送设置邮箱驗證碼", notes="发送设置邮箱驗證碼-设置邮箱使用")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.OTHER, operTitle = "发送邮箱", operDesc = "发送邮箱-设置邮箱使用")
    @PostMapping("/setMail/send")
    public Result setMailSend(@RequestBody EmailReq req) {
        Assert.notBlank(req.getEmail(),SystemError.SYS_430, "邮箱不能为空");
        TokenUser currentUser = getCurrentUser();
        return userService.setMailSend(req.getEmail(),currentUser.getId());
    }

    @ApiOperation(value="修改邮箱保存", notes="修改邮箱保存")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.UPDATE, operTitle = "修改邮箱保存", operDesc = "修改邮箱保存")
    @PostMapping("/mail/updateEmail")
    public Result updateEmail(@RequestBody @Valid UpdateEmailReq req) {
        req.setUserId(getCurrentUser().getId());
        return userService.updateEmail(req);
    }

    @ApiOperation(value="设置电邮", notes="设置电邮")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.UPDATE, operTitle = "设置电邮", operDesc = "设置电邮")
    @PostMapping("/mail/setEmail")
    public Result setEmail(@RequestBody @Valid SetEmailReq req) {
        req.setUserId(getCurrentUser().getId());
        return userService.setEmail(req);
    }

    @ApiOperation(value="退出登录", notes="注销退出登录")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.LOGOUT, operTitle = "退出登录", operDesc = "注销退出登录")
    @PostMapping("/logout")
    public Result logout() {
        try {
            Object token = getRequest().getHeaders(RedisConstants.JWT_TOKEN_HEADER).nextElement();
            String tokenStr = String.valueOf(token).replace(RedisConstants.JWT_TOKEN_PREFIX, Strings.EMPTY);
            String tokenDecrypt = RSAUtil.decryptStr(tokenStr);
            TokenUser tokenUser = JSONObject.parseObject(tokenDecrypt, TokenUser.class);

            String tokeyKey = String.format(RedisConstants.CLIENT_TOKEN_USER_KEY,LoginType.getMsgByCode(tokenUser.getLoginType())) + tokenUser.getId();
            redisTemplate.delete(tokeyKey);
        } catch (Exception e) {

        }
        return Result.success();
    }

    @ApiOperation(value="保存个人资料", notes="保存个人资料")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.ADD, operTitle = "保存个人资料", operDesc = "保存个人资料")
    @PostMapping("/saveUserInfo")
    public Result<AppUserDTO> save(@RequestBody @Valid SaveUserInfoReq req) throws Exception{
        TokenUser currentUser = getCurrentUser();
        req.setUserId(currentUser.getId());
        userService.saveUserInfo(req);
        AppUserDTO userDTO = userService.queryCacheUser(currentUser.getId());
        return Result.success(userDTO);
    }

    @ApiOperation(value="修改密码", notes="修改密码")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.UPDATE, operTitle = "修改密码", operDesc = "修改密码")
    @PostMapping("/updatePwd")
    public Result updatePwd(@RequestBody @Valid UpdatePwdReq req) throws Exception{
        TokenUser currentUser = getCurrentUser();
        req.setUserId(currentUser.getId());
        return userService.updatePwd(req);
    }

    @ApiOperation(value="修改手机号", notes="修改手机号")
    @OperationLogAnnotation(operModul = OperationLogModel.USER, operType = OperationLogType.UPDATE, operTitle = "修改手机号", operDesc = "修改手机号")
    @PostMapping("/updatePhone")
    public Result updatePhone(@RequestBody @Valid UpdatePhoneReq req) throws Exception{
        req.setContactMobileAreaCode(replacePlus(req.getContactMobileAreaCode()));
        TokenUser currentUser = getCurrentUser();
        req.setUserId(currentUser.getId());
        return userService.updatePhone(req);
    }

    @ApiOperation(value="获取手机区号数据", notes="获取手机区号数据")
    @RequestMapping(value = "/getAreaData",method = {RequestMethod.POST,RequestMethod.GET})
    public Result<List<MainDataAreaNumberListDTO>> getAreaList() throws Exception{
        MainDataAreaNumberListReq req = new MainDataAreaNumberListReq();
        req.setPageNo(1);
        req.setPageSize(10000);
        req.setStatus(0);
        PageResponse<MainDataAreaNumberListDTO> response = iMainDataAreaNumberService.list(req);
        return Result.success(response.getRecords());
    }

    @ApiOperation(value="获取当前用户信息", notes="获取当前用户信息")
    @GetMapping ("/getCurrentUserInfo")
    public Result<AppUserDTO> getUserInfo() throws Exception{
        TokenUser currentUser = getCurrentUser();
        AppUserDTO userDTO = userService.queryCacheUser(currentUser.getId());
        userDTO.setToken(getRequest().getHeader(RedisConstants.JWT_TOKEN_HEADER));
        return Result.success(userDTO);
    }

    @ApiOperation(value="获取收藏,足迹,信息,积分个数", notes="获取收藏,足迹,信息,积分个数")
    @PostMapping ("/getNum")
    public Result<NumDTO> getNum() throws Exception{
        TokenUser currentUser = getCurrentUser();
        return userService.getNum(currentUser.getId());
    }

    /**
     * 去除加号
     */
    public String replacePlus(String str) {
        return str.replaceAll("\\+","");
    }
}
